package com.construction.api.util;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import com.construction.api.domain.model.token.Payload;
import com.construction.api.enums.ResultEnum;
import com.construction.api.exception.BusinessException;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Map;

/**
 * @author dybin
 * @Date: 2021/7/1 22:32
 */
@Component
public class JwtTokenUtil {

    @Value("${jwt.token.secret-key}")
    private String secretKey;
    @Value("${jwt.token.expire-length}")
    private Long expiredLength;
    @Value("${jwt.token.des-key}")
    private String desKey;

    /**
     * 创建token
     *
     * @param payload
     * @return
     */
    public String createToken(Payload payload) {
        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime expiredTime = localDateTime.plusSeconds(expiredLength);
        payload.setIat(localDateTime.toEpochSecond(ZoneOffset.of("+8")));
        payload.setExp(expiredTime.toEpochSecond(ZoneOffset.of("+8")));
        Map<String, Object> payLoadMap = JSONUtil.parseObj(payload);
        return JWT.create()
                .addPayloads(payLoadMap)
                .setKey(secretKey.getBytes())
                .sign();
    }

    /**
     * 创建加密过的token
     *
     * @param payload
     * @return
     */
    public String createDesToken(Payload payload) {
        return encrypt(createToken(payload));
    }

    /**
     * 验证token
     *
     * @param token
     * @return
     */
    public Boolean verifyToken(String token) {
        if (ObjectUtils.isEmpty(token)) {
            throw BusinessException.of(ResultEnum.UNAUTHORIZED, "token不允许为空");
        }
        JWT jwt = JWT.of(token).setKey(secretKey.getBytes());
        if (!jwt.verify()) {
            throw BusinessException.of(ResultEnum.UNAUTHORIZED, "无效token");
        }
        Payload payload = resolvToken(token);
        if (payload.getExp() < LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"))) {
            throw BusinessException.of(ResultEnum.TOKEN_EXPIRED, "token已过期失效");
        }
        return true;
    }

    /**
     * 验证加密过的token
     *
     * @param desToken
     * @return
     */
    public Boolean verifyDesToken(String desToken) {
        String token = decrypt(desToken);
        return verifyToken(token);
    }

    /**
     * 解析token
     *
     * @param token
     * @return
     */
    public Payload resolvToken(String token) {
        JWT jwt = JWT.of(token).setKey(secretKey.getBytes());
        JSONObject jsonObject = jwt.getPayloads();
        return jsonObject.toBean(Payload.class);
    }

    /**
     * 解析加密后的token
     *
     * @param desToken
     * @return
     */
    public Payload resolvDesToken(String desToken) {
        String token = decrypt(desToken);
        return resolvToken(token);
    }

    /**
     * 刷新token
     *
     * @param token
     * @return
     */
    public String refreshToken(String token) {
        verifyToken(token);
        Payload payload = resolvToken(token);
        return createToken(payload);
    }

    /**
     * 刷新加密后的token
     *
     * @param desToken
     * @return
     */
    @SneakyThrows
    public String refreshDesToken(String desToken) {
        String token = decrypt(desToken);
        token = refreshToken(token);
        return DESUtil.encrypt(token, desKey);
    }

    public String decrypt(String desToken) {
        try {
            return DESUtil.decrypt(desToken, desKey);
        } catch (Exception e) {
            throw BusinessException.of(ResultEnum.UNAUTHORIZED, "无效token");
        }
    }

    public String encrypt(String token) {
        try {
            return DESUtil.encrypt(token, desKey);
        } catch (Exception e) {
            throw BusinessException.of(ResultEnum.BUSINESS_UNUSUAL, "生成token时出现异常, 请联系管理员");
        }
    }


}
